1use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::encoding::*;
6use crate::utils::struct_pack::*;
7use anyhow::Result;
8use serde::{Deserialize, Serialize};
9use std::io::{Read, Seek, Write};
10
11#[derive(Debug)]
12pub struct Tjs2Builder {}
14
15impl Tjs2Builder {
16 pub fn new() -> Self {
18 Self {}
19 }
20}
21
22impl ScriptBuilder for Tjs2Builder {
23 fn default_encoding(&self) -> Encoding {
24 Encoding::Utf16LE
25 }
26
27 fn build_script(
28 &self,
29 buf: Vec<u8>,
30 _filename: &str,
31 encoding: Encoding,
32 _archive_encoding: Encoding,
33 config: &ExtraConfig,
34 _archive: Option<&Box<dyn Script>>,
35 ) -> Result<Box<dyn Script>> {
36 Ok(Box::new(Tjs2::new(buf, encoding, config)?))
37 }
38
39 fn extensions(&self) -> &'static [&'static str] {
40 &["tjs"]
41 }
42
43 fn script_type(&self) -> &'static ScriptType {
44 &ScriptType::KirikiriTjs2
45 }
46
47 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
48 if buf_len >= 8 && buf.starts_with(b"TJS2100\0") {
50 return Some(40);
51 }
52 None
53 }
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
57struct DataArea {
58 byte_array: Vec<u8>,
59 short_array: Vec<i16>,
60 long_array: Vec<i32>,
61 longlong_array: Vec<i64>,
62 double_array: Vec<f64>,
63 string_array: Vec<String>,
64 octet_array: Vec<Vec<u8>>,
65}
66
67impl StructUnpack for DataArea {
68 fn unpack<R: Read + Seek>(
69 reader: &mut R,
70 big: bool,
71 encoding: Encoding,
72 info: &Option<Box<dyn std::any::Any>>,
73 ) -> Result<Self> {
74 reader.align(4)?;
75 let start_loc = reader.stream_position()?;
76 let mut data_tag = [0; 4];
77 reader.read_exact(&mut data_tag)?;
78 if &data_tag != b"DATA" {
79 return Err(anyhow::anyhow!("Invalid DATA tag"));
80 }
81 let data_size = u32::unpack(reader, big, encoding, info)?;
82 let count = u32::unpack(reader, big, encoding, info)? as usize;
83 let byte_array = reader.read_exact_vec(count)?;
84 reader.align(4)?;
85 let short_count = u32::unpack(reader, big, encoding, info)? as usize;
86 let short_array = reader.read_struct_vec(short_count, big, encoding, info)?;
87 reader.align(4)?;
88 let long_count = u32::unpack(reader, big, encoding, info)? as usize;
89 let long_array = reader.read_struct_vec(long_count, big, encoding, info)?;
90 let longlong_count = u32::unpack(reader, big, encoding, info)? as usize;
91 let longlong_array = reader.read_struct_vec(longlong_count, big, encoding, info)?;
92 let double_count = u32::unpack(reader, big, encoding, info)? as usize;
93 let double_array = reader.read_struct_vec(double_count, big, encoding, info)?;
94 let str_count = u32::unpack(reader, big, encoding, info)? as usize;
95 let mut string_array = Vec::with_capacity(str_count);
96 for _ in 0..str_count {
97 let str_len = u32::unpack(reader, big, encoding, info)? as usize;
98 let str_bytes = reader.read_exact_vec(if encoding.is_utf16le() {
99 str_len * 2
100 } else {
101 str_len
102 })?;
103 let s = decode_to_string(encoding, &str_bytes, true)?;
104 reader.align(4)?;
105 string_array.push(s);
106 }
107 let octet_count = u32::unpack(reader, big, encoding, info)? as usize;
108 let mut octet_array = Vec::with_capacity(octet_count);
109 for _ in 0..octet_count {
110 let octet_len = u32::unpack(reader, big, encoding, info)? as usize;
111 let octet_bytes = reader.read_exact_vec(octet_len)?;
112 reader.align(4)?;
113 octet_array.push(octet_bytes);
114 }
115 let end_loc = reader.stream_position()?;
116 if end_loc - start_loc != data_size as u64 {
117 return Err(anyhow::anyhow!(
118 "DATA size mismatch: expected {}, got {}",
119 data_size,
120 end_loc - start_loc
121 ));
122 }
123 Ok(DataArea {
124 byte_array,
125 short_array,
126 long_array,
127 longlong_array,
128 double_array,
129 string_array,
130 octet_array,
131 })
132 }
133}
134
135impl StructPack for DataArea {
136 fn pack<W: Write>(
137 &self,
138 writer: &mut W,
139 big: bool,
140 encoding: Encoding,
141 info: &Option<Box<dyn std::any::Any>>,
142 ) -> Result<()> {
143 writer.write_all(b"DATA")?;
144 let mut tmp = MemWriter::new();
145 tmp.write_struct(&(self.byte_array.len() as u32), big, encoding, info)?;
146 tmp.write_all(&self.byte_array)?;
147 tmp.align(4)?;
148 tmp.write_struct(&(self.short_array.len() as u32), big, encoding, info)?;
149 for v in &self.short_array {
150 tmp.write_struct(v, big, encoding, info)?;
151 }
152 tmp.align(4)?;
153 tmp.write_struct(&(self.long_array.len() as u32), big, encoding, info)?;
154 for v in &self.long_array {
155 tmp.write_struct(v, big, encoding, info)?;
156 }
157 tmp.write_struct(&(self.longlong_array.len() as u32), big, encoding, info)?;
158 for v in &self.longlong_array {
159 tmp.write_struct(v, big, encoding, info)?;
160 }
161 tmp.write_struct(&(self.double_array.len() as u32), big, encoding, info)?;
162 for v in &self.double_array {
163 tmp.write_struct(v, big, encoding, info)?;
164 }
165 tmp.write_struct(&(self.string_array.len() as u32), big, encoding, info)?;
166 for s in &self.string_array {
167 let encoded = encode_string(encoding, s, false)?;
168 let str_len = if encoding.is_utf16le() {
169 encoded.len() / 2
170 } else {
171 encoded.len()
172 };
173 tmp.write_struct(&(str_len as u32), big, encoding, info)?;
174 tmp.write_all(&encoded)?;
175 tmp.align(4)?;
176 }
177 tmp.write_struct(&(self.octet_array.len() as u32), big, encoding, info)?;
178 for o in &self.octet_array {
179 tmp.write_struct(&(o.len() as u32), big, encoding, info)?;
180 tmp.write_all(o)?;
181 tmp.align(4)?;
182 }
183 tmp.data.resize(tmp.pos, 0);
185 let data = tmp.into_inner();
186 writer.write_struct(&(data.len() as u32 + 8), big, encoding, info)?;
187 writer.write_all(&data)?;
188 Ok(())
189 }
190}
191
192#[derive(Debug)]
194pub struct Tjs2 {
195 data_area: DataArea,
196 remaing: Vec<u8>,
197 custom_yaml: bool,
198}
199
200impl Tjs2 {
201 pub fn new(buf: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
207 let mut reader = MemReader::new(buf);
208 let mut header = [0u8; 8];
209 reader.read_exact(&mut header)?;
210 if &header != b"TJS2100\0" {
211 return Err(anyhow::anyhow!("Invalid TJS2 header: {:?}", &header));
212 }
213 let _file_size = reader.read_u32()?;
214 let data_area = DataArea::unpack(&mut reader, false, encoding, &None)?;
215 let mut remaing = Vec::new();
216 reader.read_to_end(&mut remaing)?;
217 Ok(Self {
218 data_area,
219 remaing,
220 custom_yaml: config.custom_yaml,
221 })
222 }
223}
224
225impl Script for Tjs2 {
226 fn default_output_script_type(&self) -> OutputScriptType {
227 OutputScriptType::Json
228 }
229
230 fn default_format_type(&self) -> FormatOptions {
231 FormatOptions::None
232 }
233
234 fn is_output_supported(&self, _: OutputScriptType) -> bool {
235 true
236 }
237
238 fn custom_output_extension<'a>(&'a self) -> &'a str {
239 if self.custom_yaml { "yaml" } else { "json" }
240 }
241
242 fn extract_messages(&self) -> Result<Vec<Message>> {
243 let mut messages = Vec::new();
244 for s in self.data_area.string_array.iter() {
245 messages.push(Message {
246 name: None,
247 message: s.clone(),
248 });
249 }
250 Ok(messages)
251 }
252
253 fn import_messages<'a>(
254 &'a self,
255 messages: Vec<Message>,
256 mut file: Box<dyn WriteSeek + 'a>,
257 _filename: &str,
258 encoding: Encoding,
259 replacement: Option<&'a ReplacementTable>,
260 ) -> Result<()> {
261 let mut data_area = self.data_area.clone();
262 data_area.string_array = messages
263 .iter()
264 .map(|m| {
265 let mut s = m.message.clone();
266 if let Some(table) = replacement {
267 for (from, to) in &table.map {
268 s = s.replace(from, to);
269 }
270 }
271 s
272 })
273 .collect();
274 file.write_all(b"TJS2100\0")?;
275 file.write_u32(0)?; data_area.pack(&mut file, false, encoding, &None)?;
277 file.write_all(&self.remaing)?;
278 let file_size = file.stream_length()?;
279 file.write_u32_at(8, file_size as u32)?; Ok(())
281 }
282
283 fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
284 let s = if self.custom_yaml {
285 serde_yaml_ng::to_string(&self.data_area)?
286 } else {
287 serde_json::to_string_pretty(&self.data_area)?
288 };
289 let encoded = encode_string(encoding, &s, false)?;
290 let mut file = crate::utils::files::write_file(filename)?;
291 file.write_all(&encoded)?;
292 Ok(())
293 }
294
295 fn custom_import<'a>(
296 &'a self,
297 custom_filename: &'a str,
298 mut file: Box<dyn WriteSeek + 'a>,
299 encoding: Encoding,
300 output_encoding: Encoding,
301 ) -> Result<()> {
302 let data = crate::utils::files::read_file(custom_filename)?;
303 let s = decode_to_string(output_encoding, &data, true)?;
304 let data_area: DataArea = if self.custom_yaml {
305 serde_yaml_ng::from_str(&s)?
306 } else {
307 serde_json::from_str(&s)?
308 };
309 file.write_all(b"TJS2100\0")?;
310 file.write_u32(0)?; data_area.pack(&mut file, false, encoding, &None)?;
312 file.write_all(&self.remaing)?;
313 let file_size = file.stream_length()?;
314 file.write_u32_at(8, file_size as u32)?; Ok(())
316 }
317}